home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
- * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- *
- */
-
-
- # include <stdio.h>
- # include "gc_priv.h"
- # include "gc_mark.h"
-
- /* We put this here to minimize the risk of inlining. */
- /*VARARGS*/
- void GC_noop() {}
-
- mark_proc GC_mark_procs[MAX_MARK_PROCS] = {0};
- word GC_n_mark_procs = 0;
-
- /* Initialize GC_obj_kinds properly and standard free lists properly. */
- /* This must be done statically since they may be accessed before */
- /* GC_init is called. */
-
- /* PCB -- this is no longer true, GC_init must be called to use the collector. */
-
- /* It's done here, since we need to deal with mark descriptors. */
-
- struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
- /* PTRFREE */ { 0, 0, /* initialized below. */
- 0 | DS_LENGTH, FALSE, FALSE },
- /* NORMAL */ { 0, 0, /* initialized below. */
- # ifdef ADD_BYTE_AT_END
- (word)(WORDS_TO_BYTES(-1)) | DS_LENGTH,
- # else
- 0 | DS_LENGTH,
- # endif
- TRUE /* add length to descr */, TRUE },
- /* UNCOLLECTABLE */
- { 0, 0, /* initialized below. */
- 0 | DS_LENGTH, TRUE /* add length to descr */, TRUE },
- # ifdef STUBBORN_ALLOC
- /*STUBBORN*/ { 0, 0, /* initialized below. */
- 0 | DS_LENGTH, TRUE /* add length to descr */, TRUE },
- # endif
- };
-
- /* PCB - had to change these to runtime initialization since no longer static. */
-
- void GC_init_mark()
- {
- GC_obj_kinds[PTRFREE].ok_freelist = &GC_aobjfreelist[0];
- GC_obj_kinds[PTRFREE].ok_reclaim_list = &GC_areclaim_list[0];
-
- GC_obj_kinds[NORMAL].ok_freelist = &GC_objfreelist[0];
- GC_obj_kinds[NORMAL].ok_reclaim_list = &GC_reclaim_list[0];
-
- GC_obj_kinds[UNCOLLECTABLE].ok_freelist = &GC_uobjfreelist[0];
- GC_obj_kinds[UNCOLLECTABLE].ok_reclaim_list = &GC_ureclaim_list[0];
-
- # ifdef STUBBORN_ALLOC
- GC_obj_kinds[STUBBORN].ok_freelist = &GC_sobjfreelist[0];
- GC_obj_kinds[STUBBORN].ok_reclaim_list = &GC_sreclaim_list[0];
- #endif
- }
-
-
- # ifdef STUBBORN_ALLOC
- int GC_n_kinds = 4;
- # else
- int GC_n_kinds = 3;
- # endif
-
-
- # define INITIAL_MARK_STACK_SIZE (1*HBLKSIZE)
- /* INITIAL_MARK_STACK_SIZE * sizeof(mse) should be a */
- /* multiple of HBLKSIZE. */
-
- /*
- * Limits of stack for GC_mark routine.
- * All ranges between GC_mark_stack(incl.) and GC_mark_stack_top(incl.) still
- * need to be marked from.
- */
-
- word GC_n_rescuing_pages; /* Number of dirty pages we marked from */
- /* excludes ptrfree pages, etc. */
-
- mse * GC_mark_stack;
-
- word GC_mark_stack_size = 0;
-
- mse * GC_mark_stack_top;
-
- static struct hblk * scan_ptr;
-
- mark_state_t GC_mark_state = MS_NONE;
-
- bool GC_mark_stack_too_small = FALSE;
-
- bool GC_objects_are_marked = FALSE; /* Are there collectable marked */
- /* objects in the heap? */
-
- bool GC_collection_in_progress()
- {
- return(GC_mark_state != MS_NONE);
- }
-
- /* clear all mark bits in the header */
- void GC_clear_hdr_marks(hhdr)
- register hdr * hhdr;
- {
- BZERO(hhdr -> hb_marks, MARK_BITS_SZ*sizeof(word));
- }
-
- /*
- * Clear all mark bits associated with block h.
- */
- /*ARGSUSED*/
- static void clear_marks_for_block(h, dummy)
- struct hblk *h;
- word dummy;
- {
- register hdr * hhdr = HDR(h);
-
- if (hhdr -> hb_obj_kind == UNCOLLECTABLE) return;
- /* Mark bit for these is cleared only once the object is */
- /* explicitly deallocated. This either frees the block, or */
- /* the bit is cleared once the object is on the free list. */
- GC_clear_hdr_marks(hhdr);
- }
-
- /* Slow but general routines for setting/clearing/asking about mark bits */
- void GC_set_mark_bit(p)
- ptr_t p;
- {
- register struct hblk *h = HBLKPTR(p);
- register hdr * hhdr = HDR(h);
- register int word_no = (word *)p - (word *)h;
-
- set_mark_bit_from_hdr(hhdr, word_no);
- }
-
- void GC_clear_mark_bit(p)
- ptr_t p;
- {
- register struct hblk *h = HBLKPTR(p);
- register hdr * hhdr = HDR(h);
- register int word_no = (word *)p - (word *)h;
-
- clear_mark_bit_from_hdr(hhdr, word_no);
- }
-
- bool GC_is_marked(p)
- ptr_t p;
- {
- register struct hblk *h = HBLKPTR(p);
- register hdr * hhdr = HDR(h);
- register int word_no = (word *)p - (word *)h;
-
- return(mark_bit_from_hdr(hhdr, word_no));
- }
-
-
- /*
- * Clear mark bits in all allocated heap blocks. This invalidates
- * the marker invariant, and sets GC_mark_state to reflect this.
- * (This implicitly starts marking to reestablish the
- */
- void GC_clear_marks()
- {
- GC_apply_to_all_blocks(clear_marks_for_block, (word)0);
- GC_objects_are_marked = FALSE;
- GC_mark_state = MS_INVALID;
- scan_ptr = 0;
- # ifdef GATHERSTATS
- /* Counters reflect currently marked objects: reset here */
- GC_composite_in_use = 0;
- GC_atomic_in_use = 0;
- # endif
-
- }
-
- /* Initiate full marking. */
- void GC_initiate_full()
- {
- # ifdef PRINTSTATS
- GC_printf2("***>Full mark for collection %lu after %ld allocd bytes\n",
- (unsigned long) GC_gc_no+1,
- (long)WORDS_TO_BYTES(GC_words_allocd));
- # endif
- GC_promote_black_lists();
- GC_reclaim_or_delete_all();
- GC_clear_marks();
- GC_read_dirty();
- # ifdef STUBBORN_ALLOC
- GC_read_changed();
- # endif
- # ifdef CHECKSUMS
- {
- extern void GC_check_dirty();
-
- GC_check_dirty();
- }
- # endif
- # ifdef GATHERSTATS
- GC_n_rescuing_pages = 0;
- # endif
- }
-
- /* Initiate partial marking. */
- /*ARGSUSED*/
- void GC_initiate_partial()
- {
- if (GC_dirty_maintained) GC_read_dirty();
- # ifdef STUBBORN_ALLOC
- GC_read_changed();
- # endif
- # ifdef CHECKSUMS
- {
- extern void GC_check_dirty();
-
- if (GC_dirty_maintained) GC_check_dirty();
- }
- # endif
- # ifdef GATHERSTATS
- GC_n_rescuing_pages = 0;
- # endif
- if (GC_mark_state == MS_NONE) {
- GC_mark_state = MS_PUSH_RESCUERS;
- } else if (GC_mark_state != MS_INVALID) {
- ABORT("unexpected state");
- } /* else this is really a full collection, and mark */
- /* bits are invalid. */
- scan_ptr = 0;
- }
-
-
- static void alloc_mark_stack();
-
- /* Perform a small amount of marking. */
- /* We try to touch roughly a page of memory. */
- /* Return TRUE if we just finished a mark phase. */
- bool GC_mark_some()
- {
- switch(GC_mark_state) {
- case MS_NONE:
- return(FALSE);
-
- case MS_PUSH_RESCUERS:
- if (GC_mark_stack_top
- >= GC_mark_stack + INITIAL_MARK_STACK_SIZE/4) {
- GC_mark_from_mark_stack();
- return(FALSE);
- } else {
- scan_ptr = GC_push_next_marked_dirty(scan_ptr);
- if (scan_ptr == 0) {
- # ifdef PRINTSTATS
- GC_printf1("Marked from %lu dirty pages\n",
- (unsigned long)GC_n_rescuing_pages);
- # endif
- GC_push_roots(FALSE);
- GC_objects_are_marked = TRUE;
- if (GC_mark_state != MS_INVALID) {
- GC_mark_state = MS_ROOTS_PUSHED;
- }
- }
- }
- return(FALSE);
-
- case MS_PUSH_UNCOLLECTABLE:
- if (GC_mark_stack_top
- >= GC_mark_stack + INITIAL_MARK_STACK_SIZE/4) {
- GC_mark_from_mark_stack();
- return(FALSE);
- } else {
- scan_ptr = GC_push_next_marked_uncollectable(scan_ptr);
- if (scan_ptr == 0) {
- GC_push_roots(TRUE);
- GC_objects_are_marked = TRUE;
- if (GC_mark_state != MS_INVALID) {
- GC_mark_state = MS_ROOTS_PUSHED;
- }
- }
- }
- return(FALSE);
-
- case MS_ROOTS_PUSHED:
- if (GC_mark_stack_top >= GC_mark_stack) {
- GC_mark_from_mark_stack();
- return(FALSE);
- } else {
- GC_mark_state = MS_NONE;
- if (GC_mark_stack_too_small) {
- alloc_mark_stack(2*GC_mark_stack_size);
- }
- return(TRUE);
- }
-
- case MS_INVALID:
- case MS_PARTIALLY_INVALID:
- if (!GC_objects_are_marked) {
- GC_mark_state = MS_PUSH_UNCOLLECTABLE;
- return(FALSE);
- }
- if (GC_mark_stack_top >= GC_mark_stack) {
- GC_mark_from_mark_stack();
- return(FALSE);
- }
- if (scan_ptr == 0
- && (GC_mark_state == MS_INVALID || GC_mark_stack_too_small)) {
- alloc_mark_stack(2*GC_mark_stack_size);
- GC_mark_state = MS_PARTIALLY_INVALID;
- }
- scan_ptr = GC_push_next_marked(scan_ptr);
- if (scan_ptr == 0 && GC_mark_state == MS_PARTIALLY_INVALID) {
- GC_push_roots(TRUE);
- GC_objects_are_marked = TRUE;
- if (GC_mark_state != MS_INVALID) {
- GC_mark_state = MS_ROOTS_PUSHED;
- }
- }
- return(FALSE);
- default:
- ABORT("GC_mark_some: bad state");
- return(FALSE);
- }
- }
-
-
- bool GC_mark_stack_empty()
- {
- return(GC_mark_stack_top < GC_mark_stack);
- }
-
- #ifdef PROF_MARKER
- word GC_prof_array[10];
- # define PROF(n) GC_prof_array[n]++
- #else
- # define PROF(n)
- #endif
-
- /* Given a pointer to someplace other than a small object page or the */
- /* first page of a large object, return a pointer either to the */
- /* start of the large object or NIL. */
- /* In the latter case black list the address current. */
- /* Returns NIL without black listing if current points to a block */
- /* with IGNORE_OFF_PAGE set. */
- /*ARGSUSED*/
- word GC_find_start(current, hhdr)
- register word current;
- register hdr * hhdr;
- {
- # ifdef ALL_INTERIOR_POINTERS
- if (hhdr != 0) {
- register word orig = current;
-
- current = (word)HBLKPTR(current) + HDR_BYTES;
- do {
- current = current - HBLKSIZE*(int)hhdr;
- hhdr = HDR(current);
- } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
- /* current points to the start of the large object */
- if (hhdr -> hb_flags & IGNORE_OFF_PAGE) return(0);
- if ((word *)orig - (word *)current
- >= (ptrdiff_t)(hhdr->hb_sz)) {
- /* Pointer past the end of the block */
- GC_ADD_TO_BLACK_LIST_NORMAL(orig);
- return(0);
- }
- return(current);
- } else {
- GC_ADD_TO_BLACK_LIST_NORMAL(current);
- return(0);
- }
- # else
- GC_ADD_TO_BLACK_LIST_NORMAL(current);
- return(0);
- # endif
- }
-
- mse * GC_signal_mark_stack_overflow(msp)
- mse * msp;
- {
- GC_mark_state = MS_INVALID;
- # ifdef PRINTSTATS
- GC_printf1("Mark stack overflow; current size = %lu entries\n",
- GC_mark_stack_size);
- # endif
- return(msp-INITIAL_MARK_STACK_SIZE/8);
- }
-
-
- /*
- * Mark objects pointed to by the regions described by
- * mark stack entries between GC_mark_stack and GC_mark_stack_top,
- * inclusive. Assumes the upper limit of a mark stack entry
- * is never 0. A mark stack entry never has size 0.
- * We try to traverse on the order of a hblk of memory before we return.
- * Caller is responsible for calling this until the mark stack is empty.
- */
- void GC_mark_from_mark_stack()
- {
- mse * GC_mark_stack_reg = GC_mark_stack;
- mse * GC_mark_stack_top_reg = GC_mark_stack_top;
- mse * mark_stack_limit = &(GC_mark_stack[GC_mark_stack_size]);
- int credit = HBLKSIZE; /* Remaining credit for marking work */
- register word * current_p; /* Pointer to current candidate ptr. */
- register word current; /* Candidate pointer. */
- register word * limit; /* (Incl) limit of current candidate */
- /* range */
- register word descr;
- register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
- register ptr_t least_ha = GC_least_plausible_heap_addr;
- # define SPLIT_RANGE_WORDS 128 /* Must be power of 2. */
-
- GC_objects_are_marked = TRUE;
- # ifdef OS2 /* Use untweaked version to circumvent compiler problem */
- while (GC_mark_stack_top_reg >= GC_mark_stack_reg && credit >= 0) {
- # else
- while ((((ptr_t)GC_mark_stack_top_reg - (ptr_t)GC_mark_stack_reg) | credit)
- >= 0) {
- # endif
- current_p = GC_mark_stack_top_reg -> mse_start;
- descr = GC_mark_stack_top_reg -> mse_descr;
- retry:
- if (descr & ((~(WORDS_TO_BYTES(SPLIT_RANGE_WORDS) - 1)) | DS_TAGS)) {
- word tag = descr & DS_TAGS;
-
- switch(tag) {
- case DS_LENGTH:
- /* Large length. */
- /* Process part of the range to avoid pushing too much on the */
- /* stack. */
- GC_mark_stack_top_reg -> mse_start =
- limit = current_p + SPLIT_RANGE_WORDS-1;
- GC_mark_stack_top_reg -> mse_descr -=
- WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
- /* Make sure that pointers overlapping the two ranges are */
- /* considered. */
- limit += sizeof(word) - ALIGNMENT;
- break;
- case DS_BITMAP:
- GC_mark_stack_top_reg--;
- descr &= ~DS_TAGS;
- credit -= WORDS_TO_BYTES(WORDSZ/2); /* guess */
- while (descr != 0) {
- if ((signed_word)descr < 0) {
- current = *current_p++;
- descr <<= 1;
- if ((ptr_t)current < least_ha) continue;
- if ((ptr_t)current >= greatest_ha) continue;
- PUSH_CONTENTS(current, GC_mark_stack_top_reg, mark_stack_limit);
- } else {
- descr <<= 1;
- current_p++;
- }
- }
- continue;
- case DS_PROC:
- GC_mark_stack_top_reg--;
- credit -= PROC_BYTES;
- GC_mark_stack_top_reg =
- (*PROC(descr))
- (current_p, GC_mark_stack_top_reg,
- mark_stack_limit, ENV(descr));
- continue;
- case DS_PER_OBJECT:
- descr = *(word *)((ptr_t)current_p + descr - tag);
- goto retry;
- }
- } else {
- GC_mark_stack_top_reg--;
- limit = (word *)(((ptr_t)current_p) + (word)descr);
- }
- /* The simple case in which we're scanning a range. */
- credit -= (ptr_t)limit - (ptr_t)current_p;
- limit -= 1;
- while (current_p <= limit) {
- current = *current_p;
- current_p = (word *)((char *)current_p + ALIGNMENT);
- if ((ptr_t)current < least_ha) continue;
- if ((ptr_t)current >= greatest_ha) continue;
- PUSH_CONTENTS(current, GC_mark_stack_top_reg, mark_stack_limit);
- }
- }
- GC_mark_stack_top = GC_mark_stack_top_reg;
- }
-
- /* Allocate or reallocate space for mark stack of size s words */
- /* May silently fail. */
- static void alloc_mark_stack(n)
- word n;
- {
- mse * new_stack = (mse *)GC_scratch_alloc(n * sizeof(struct ms_entry));
-
- GC_mark_stack_too_small = FALSE;
- if (GC_mark_stack_size != 0) {
- if (new_stack != 0) {
- word displ = HBLKDISPL(GC_mark_stack);
- word size = GC_mark_stack_size * sizeof(struct ms_entry);
-
- /* Recycle old space */
- if (displ == 0) {
- GC_add_to_heap((struct hblk *)GC_mark_stack, size);
- } else {
- GC_add_to_heap((struct hblk *)
- ((word)GC_mark_stack - displ + HBLKSIZE),
- size - HBLKSIZE);
- }
- GC_mark_stack = new_stack;
- GC_mark_stack_size = n;
- # ifdef PRINTSTATS
- GC_printf1("Grew mark stack to %lu frames\n",
- (unsigned long) GC_mark_stack_size);
- # endif
- } else {
- # ifdef PRINTSTATS
- GC_printf1("Failed to grow mark stack to %lu frames\n",
- (unsigned long) n);
- # endif
- }
- } else {
- if (new_stack == 0) {
- GC_err_printf0("No space for mark stack\n");
- EXIT();
- }
- GC_mark_stack = new_stack;
- GC_mark_stack_size = n;
- }
- GC_mark_stack_top = GC_mark_stack-1;
- }
-
- void GC_mark_init()
- {
- alloc_mark_stack(INITIAL_MARK_STACK_SIZE);
- }
-
- /*
- * Push all locations between b and t onto the mark stack.
- * b is the first location to be checked. t is one past the last
- * location to be checked.
- * Should only be used if there is no possibility of mark stack
- * overflow.
- */
- void GC_push_all(bottom, top)
- ptr_t bottom;
- ptr_t top;
- {
- register word length;
-
- bottom = (ptr_t)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
- top = (ptr_t)(((word) top) & ~(ALIGNMENT-1));
- if (top == 0 || bottom == top) return;
- GC_mark_stack_top++;
- if (GC_mark_stack_top >= GC_mark_stack + GC_mark_stack_size) {
- ABORT("unexpected mark stack overflow");
- }
- length = top - bottom;
- # if DS_TAGS > ALIGNMENT - 1
- length += DS_TAGS;
- length &= ~DS_TAGS;
- # endif
- GC_mark_stack_top -> mse_start = (word *)bottom;
- GC_mark_stack_top -> mse_descr = length;
- }
-
- /*
- * Analogous to the above, but push only those pages that may have been
- * dirtied. A block h is assumed dirty if dirty_fn(h) != 0.
- * We use push_fn to actually push the block.
- * Will not overflow mark stack if push_fn pushes a small fixed number
- * of entries. (This is invoked only if push_fn pushes a single entry,
- * or if it marks each object before pushing it, thus ensuring progress
- * in the event of a stack overflow.)
- */
- void GC_push_dirty(bottom, top, dirty_fn, push_fn)
- ptr_t bottom;
- ptr_t top;
- int (*dirty_fn)(/* struct hblk * h */);
- void (*push_fn)(/* ptr_t bottom, ptr_t top */);
- {
- register struct hblk * h;
-
- bottom = (ptr_t)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
- top = (ptr_t)(((long) top) & ~(ALIGNMENT-1));
-
- if (top == 0 || bottom == top) return;
- h = HBLKPTR(bottom + HBLKSIZE);
- if (top <= (ptr_t) h) {
- if ((*dirty_fn)(h-1)) {
- (*push_fn)(bottom, top);
- }
- return;
- }
- if ((*dirty_fn)(h-1)) {
- (*push_fn)(bottom, (ptr_t)h);
- }
- while ((ptr_t)(h+1) <= top) {
- if ((*dirty_fn)(h)) {
- if ((word)(GC_mark_stack_top - GC_mark_stack)
- > 3 * GC_mark_stack_size / 4) {
- /* Danger of mark stack overflow */
- (*push_fn)((ptr_t)h, top);
- return;
- } else {
- (*push_fn)((ptr_t)h, (ptr_t)(h+1));
- }
- }
- h++;
- }
- if ((ptr_t)h != top) {
- if ((*dirty_fn)(h)) {
- (*push_fn)((ptr_t)h, top);
- }
- }
- if (GC_mark_stack_top >= GC_mark_stack + GC_mark_stack_size) {
- ABORT("unexpected mark stack overflow");
- }
- }
-
- # ifndef SMALL_CONFIG
- void GC_push_conditional(bottom, top, all)
- ptr_t bottom;
- ptr_t top;
- {
- if (all) {
- if (GC_dirty_maintained) {
- # ifdef PROC_VDB
- /* Pages that were never dirtied cannot contain pointers */
- GC_push_dirty(bottom, top, GC_page_was_ever_dirty, GC_push_all);
- # else
- GC_push_all(bottom, top);
- # endif
- } else {
- GC_push_all(bottom, top);
- }
- } else {
- GC_push_dirty(bottom, top, GC_page_was_dirty, GC_push_all);
- }
- }
- #endif
-
- /*
- * Push a single value onto mark stack. Mark from the object pointed to by p.
- * GC_push_one is normally called by GC_push_regs, and thus must be defined.
- * P is considered valid even if it is an interior pointer.
- * Previously marked objects are not pushed. Hence we make progress even
- * if the mark stack overflows.
- */
- # define GC_PUSH_ONE_STACK(p) \
- if ((ptr_t)(p) >= GC_least_plausible_heap_addr \
- && (ptr_t)(p) < GC_greatest_plausible_heap_addr) { \
- GC_push_one_checked(p,TRUE); \
- }
-
- /*
- * As above, but interior pointer recognition as for
- * normal for heap pointers.
- */
- # ifdef ALL_INTERIOR_POINTERS
- # define AIP TRUE
- # else
- # define AIP FALSE
- # endif
- # define GC_PUSH_ONE_HEAP(p) \
- if ((ptr_t)(p) >= GC_least_plausible_heap_addr \
- && (ptr_t)(p) < GC_greatest_plausible_heap_addr) { \
- GC_push_one_checked(p,AIP); \
- }
-
- # ifdef MSWIN32
- void __cdecl GC_push_one(p)
- # else
- void GC_push_one(p)
- # endif
- word p;
- {
- GC_PUSH_ONE_STACK(p);
- }
-
- # ifdef __STDC__
- # define BASE(p) (word)GC_base((void *)(p))
- # else
- # define BASE(p) (word)GC_base((char *)(p))
- # endif
-
- /* As above, but argument passed preliminary test. */
- void GC_push_one_checked(p, interior_ptrs)
- register word p;
- register bool interior_ptrs;
- {
- register word r;
- register hdr * hhdr;
- register int displ;
-
- GET_HDR(p, hhdr);
- if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
- if (hhdr != 0 && interior_ptrs) {
- r = BASE(p);
- hhdr = HDR(r);
- displ = BYTES_TO_WORDS(HBLKDISPL(r));
- } else {
- hhdr = 0;
- }
- } else {
- register map_entry_type map_entry;
-
- displ = HBLKDISPL(p);
- map_entry = MAP_ENTRY((hhdr -> hb_map), displ);
- if (map_entry == OBJ_INVALID) {
- if (interior_ptrs) {
- r = BASE(p);
- displ = BYTES_TO_WORDS(HBLKDISPL(r));
- if (r == 0) hhdr = 0;
- } else {
- hhdr = 0;
- }
- } else {
- displ = BYTES_TO_WORDS(displ);
- displ -= map_entry;
- r = (word)((word *)(HBLKPTR(p)) + displ);
- }
- }
- /* If hhdr != 0 then r == GC_base(p), only we did it faster. */
- /* displ is the word index within the block. */
- if (hhdr == 0) {
- if (interior_ptrs) {
- GC_add_to_black_list_stack(p);
- } else {
- GC_ADD_TO_BLACK_LIST_NORMAL(p);
- }
- } else {
- if (!mark_bit_from_hdr(hhdr, displ)) {
- set_mark_bit_from_hdr(hhdr, displ);
- PUSH_OBJ((word *)r, hhdr, GC_mark_stack_top,
- &(GC_mark_stack[GC_mark_stack_size]));
- }
- }
- }
-
- /*
- * A version of GC_push_all that treats all interior pointers as valid
- */
- void GC_push_all_stack(bottom, top)
- ptr_t bottom;
- ptr_t top;
- {
- # ifdef ALL_INTERIOR_POINTERS
- GC_push_all(bottom, top);
- # else
- word * b = (word *)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
- word * t = (word *)(((long) top) & ~(ALIGNMENT-1));
- register word *p;
- register word q;
- register word *lim;
- register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
- register ptr_t least_ha = GC_least_plausible_heap_addr;
- # define GC_greatest_plausible_heap_addr greatest_ha
- # define GC_least_plausible_heap_addr least_ha
-
- if (top == 0) return;
- /* check all pointers in range and put in push if they appear */
- /* to be valid. */
- lim = t - 1 /* longword */;
- for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) {
- q = *p;
- GC_PUSH_ONE_STACK(q);
- }
- # undef GC_greatest_plausible_heap_addr
- # undef GC_least_plausible_heap_addr
- # endif
- }
-
- #ifndef SMALL_CONFIG
- /* Push all objects reachable from marked objects in the given block */
- /* of size 1 objects. */
- void GC_push_marked1(h, hhdr)
- struct hblk *h;
- register hdr * hhdr;
- {
- word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
- register word *p;
- word *plim;
- register int i;
- register word q;
- register word mark_word;
- register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
- register ptr_t least_ha = GC_least_plausible_heap_addr;
- # define GC_greatest_plausible_heap_addr greatest_ha
- # define GC_least_plausible_heap_addr least_ha
-
- p = (word *)(h->hb_body);
- plim = (word *)(((word)h) + HBLKSIZE);
-
- /* go through all words in block */
- while( p < plim ) {
- mark_word = *mark_word_addr++;
- i = 0;
- while(mark_word != 0) {
- if (mark_word & 1) {
- q = p[i];
- GC_PUSH_ONE_HEAP(q);
- }
- i++;
- mark_word >>= 1;
- }
- p += WORDSZ;
- }
- # undef GC_greatest_plausible_heap_addr
- # undef GC_least_plausible_heap_addr
- }
-
-
- /* Push all objects reachable from marked objects in the given block */
- /* of size 2 objects. */
- void GC_push_marked2(h, hhdr)
- struct hblk *h;
- register hdr * hhdr;
- {
- word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
- register word *p;
- word *plim;
- register int i;
- register word q;
- register word mark_word;
- register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
- register ptr_t least_ha = GC_least_plausible_heap_addr;
- # define GC_greatest_plausible_heap_addr greatest_ha
- # define GC_least_plausible_heap_addr least_ha
-
- p = (word *)(h->hb_body);
- plim = (word *)(((word)h) + HBLKSIZE);
-
- /* go through all words in block */
- while( p < plim ) {
- mark_word = *mark_word_addr++;
- i = 0;
- while(mark_word != 0) {
- if (mark_word & 1) {
- q = p[i];
- GC_PUSH_ONE_HEAP(q);
- q = p[i+1];
- GC_PUSH_ONE_HEAP(q);
- }
- i += 2;
- mark_word >>= 2;
- }
- p += WORDSZ;
- }
- # undef GC_greatest_plausible_heap_addr
- # undef GC_least_plausible_heap_addr
- }
-
- /* Push all objects reachable from marked objects in the given block */
- /* of size 4 objects. */
- /* There is a risk of mark stack overflow here. But we handle that. */
- /* And only unmarked objects get pushed, so it's not very likely. */
- void GC_push_marked4(h, hhdr)
- struct hblk *h;
- register hdr * hhdr;
- {
- word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
- register word *p;
- word *plim;
- register int i;
- register word q;
- register word mark_word;
- register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
- register ptr_t least_ha = GC_least_plausible_heap_addr;
- # define GC_greatest_plausible_heap_addr greatest_ha
- # define GC_least_plausible_heap_addr least_ha
-
- p = (word *)(h->hb_body);
- plim = (word *)(((word)h) + HBLKSIZE);
-
- /* go through all words in block */
- while( p < plim ) {
- mark_word = *mark_word_addr++;
- i = 0;
- while(mark_word != 0) {
- if (mark_word & 1) {
- q = p[i];
- GC_PUSH_ONE_HEAP(q);
- q = p[i+1];
- GC_PUSH_ONE_HEAP(q);
- q = p[i+2];
- GC_PUSH_ONE_HEAP(q);
- q = p[i+3];
- GC_PUSH_ONE_HEAP(q);
- }
- i += 4;
- mark_word >>= 4;
- }
- p += WORDSZ;
- }
- # undef GC_greatest_plausible_heap_addr
- # undef GC_least_plausible_heap_addr
- }
-
- #endif /* SMALL_CONFIG */
-
- /* Push all objects reachable from marked objects in the given block */
- void GC_push_marked(h, hhdr)
- struct hblk *h;
- register hdr * hhdr;
- {
- register int sz = hhdr -> hb_sz;
- register word * p;
- register int word_no;
- register word * lim;
- register mse * GC_mark_stack_top_reg;
- register mse * mark_stack_limit = &(GC_mark_stack[GC_mark_stack_size]);
-
- /* Some quick shortcuts: */
- if (hhdr -> hb_obj_kind == PTRFREE) return;
- if (GC_block_empty(hhdr)/* nothing marked */) return;
- # ifdef GATHERSTATS
- GC_n_rescuing_pages++;
- # endif
- GC_objects_are_marked = TRUE;
- if (sz > MAXOBJSZ) {
- lim = (word *)(h + 1);
- } else {
- lim = (word *)(h + 1) - sz;
- }
-
- switch(sz) {
- # ifndef SMALL_CONFIG
- case 1:
- GC_push_marked1(h, hhdr);
- break;
- case 2:
- GC_push_marked2(h, hhdr);
- break;
- case 4:
- GC_push_marked4(h, hhdr);
- break;
- # endif
- default:
- GC_mark_stack_top_reg = GC_mark_stack_top;
- for (p = (word *)h + HDR_WORDS, word_no = HDR_WORDS; p <= lim;
- p += sz, word_no += sz) {
- /* This needs manual optimization: */
- if (mark_bit_from_hdr(hhdr, word_no)) {
- /* Mark from fields inside the object */
- PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top_reg, mark_stack_limit);
- # ifdef GATHERSTATS
- /* Subtract this object from total, since it was */
- /* added in twice. */
- GC_composite_in_use -= sz;
- # endif
- }
- }
- GC_mark_stack_top = GC_mark_stack_top_reg;
- }
- }
-
- #ifndef SMALL_CONFIG
- /* Test whether any page in the given block is dirty */
- bool GC_block_was_dirty(h, hhdr)
- struct hblk *h;
- register hdr * hhdr;
- {
- register int sz = hhdr -> hb_sz;
-
- if (sz < MAXOBJSZ) {
- return(GC_page_was_dirty(h));
- } else {
- register ptr_t p = (ptr_t)h;
- sz += HDR_WORDS;
- sz = WORDS_TO_BYTES(sz);
- while (p < (ptr_t)h + sz) {
- if (GC_page_was_dirty((struct hblk *)p)) return(TRUE);
- p += HBLKSIZE;
- }
- return(FALSE);
- }
- }
- #endif /* SMALL_CONFIG */
-
- /* Similar to GC_push_next_marked, but return address of next block */
- struct hblk * GC_push_next_marked(h)
- struct hblk *h;
- {
- register hdr * hhdr;
-
- h = GC_next_block(h);
- if (h == 0) return(0);
- hhdr = HDR(h);
- GC_push_marked(h, hhdr);
- return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
- }
-
- #ifndef SMALL_CONFIG
- /* Identical to above, but mark only from dirty pages */
- struct hblk * GC_push_next_marked_dirty(h)
- struct hblk *h;
- {
- register hdr * hhdr = HDR(h);
-
- if (!GC_dirty_maintained) { ABORT("dirty bits not set up"); }
- for (;;) {
- h = GC_next_block(h);
- if (h == 0) return(0);
- hhdr = HDR(h);
- # ifdef STUBBORN_ALLOC
- if (hhdr -> hb_obj_kind == STUBBORN) {
- if (GC_page_was_changed(h) && GC_block_was_dirty(h, hhdr)) {
- break;
- }
- } else {
- if (GC_block_was_dirty(h, hhdr)) break;
- }
- # else
- if (GC_block_was_dirty(h, hhdr)) break;
- # endif
- h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
- }
- GC_push_marked(h, hhdr);
- return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
- }
- #endif
-
- /* Similar to above, but for uncollectable pages. Needed since we */
- /* do not clear marks for such pages, even for full collections. */
- struct hblk * GC_push_next_marked_uncollectable(h)
- struct hblk *h;
- {
- register hdr * hhdr = HDR(h);
-
- for (;;) {
- h = GC_next_block(h);
- if (h == 0) return(0);
- hhdr = HDR(h);
- if (hhdr -> hb_obj_kind == UNCOLLECTABLE) break;
- h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
- }
- GC_push_marked(h, hhdr);
- return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
- }
-
-
-